import { createSlice, type PayloadAction } from '@reduxjs/toolkit'
import type { ComponentInfo, ComponentState } from './types'
import { produce } from 'immer'
import { ComponentPropsType } from '../../components/question-components'
import { getNextSelectedId, insertNewComponent } from './utils'
import cloneDeep from 'lodash.clonedeep'
import { nanoid } from 'nanoid'
import { arrayMove } from '@dnd-kit/sortable'

const initialState: ComponentState = {
  selectedId: '',
  componentList: [],
  copiedComponent: null,
}

const componentSlice = createSlice({
  name: 'component',
  initialState,
  reducers: {
    resetComponents: (state: ComponentState, action: PayloadAction<ComponentState>) => {
      return { ...state, ...action.payload }
    },

    changeSelectedId: produce((draft: ComponentState, action: PayloadAction<string>) => {
      draft.selectedId = action.payload
    }),

    addComponent: produce((draft: ComponentState, action: PayloadAction<ComponentInfo>) => {
      const newComponent = action.payload

      insertNewComponent(draft, newComponent)
    }),

    changeComponentProps: produce(
      (draft: ComponentState, action: PayloadAction<{ fe_id: string; newProps: ComponentPropsType }>) => {
        const { fe_id, newProps } = action.payload

        const curComp = draft.componentList.find(c => c.fe_id === fe_id)
        if (curComp) {
          curComp.props = { ...curComp.props, ...newProps }
        }
      }
    ),

    removeSelectedComponent: produce((draft: ComponentState) => {
      const { componentList, selectedId: removedId } = draft

      const newSelectedId = getNextSelectedId(removedId, componentList)
      draft.selectedId = newSelectedId

      const index = componentList.findIndex(c => c.fe_id === removedId)
      draft.componentList.splice(index, 1)
    }),

    changeComponentHidden: produce(
      (draft: ComponentState, action: PayloadAction<{ fe_id: string; isHidden: boolean }>) => {
        const { componentList } = draft
        const { fe_id, isHidden } = action.payload

        let newSelectedId = ''
        if (isHidden) {
          newSelectedId = getNextSelectedId(fe_id, componentList)
        } else {
          newSelectedId = fe_id
        }

        draft.selectedId = newSelectedId

        const curComp = componentList.find(c => c.fe_id === fe_id)
        if (curComp) {
          curComp.isHidden = isHidden
        }
      }
    ),

    toggleComponentLock: produce((draft: ComponentState, action: PayloadAction<string>) => {
      const { componentList } = draft
      const fe_id = action.payload

      const curComp = componentList.find(c => c.fe_id === fe_id)
      if (curComp) {
        curComp.isLocked = !curComp.isLocked
      }
    }),

    copySelectedComponent: produce((draft: ComponentState) => {
      const { selectedId, componentList } = draft

      const selectedComponent = componentList.find(c => c.fe_id === selectedId)
      if (selectedComponent == null) return

      draft.copiedComponent = cloneDeep(selectedComponent)
    }),

    pasteCopiedComponent: produce((draft: ComponentState) => {
      const { copiedComponent } = draft
      if (copiedComponent == null) return

      copiedComponent.fe_id = nanoid()

      insertNewComponent(draft, copiedComponent)
    }),

    selectPrevComponent: produce((draft: ComponentState) => {
      const { selectedId, componentList } = draft

      let selectedIndex = componentList.findIndex(c => c.fe_id === selectedId)
      if (selectedIndex < 0) return

      if (selectedIndex <= 0) {
        selectedIndex = componentList.length - 1
      } else {
        selectedIndex--
      }

      draft.selectedId = componentList[selectedIndex].fe_id
    }),

    selectNextComponent: produce((draft: ComponentState) => {
      const { selectedId, componentList } = draft

      let selectedIndex = componentList.findIndex(c => c.fe_id === selectedId)
      if (selectedIndex < 0) return

      if (selectedIndex === componentList.length - 1) {
        selectedIndex = 0
      } else {
        selectedIndex++
      }

      draft.selectedId = componentList[selectedIndex].fe_id
    }),

    changeComponentTitle: produce((draft: ComponentState, action: PayloadAction<{ fe_id: string; title: string }>) => {
      const { fe_id, title } = action.payload
      const curComp = draft.componentList.find(c => c.fe_id === fe_id)

      if (curComp) curComp.title = title
    }),

    moveComponent: produce((draft: ComponentState, action: PayloadAction<{ oldIndex: number; newIndex: number }>) => {
      const { componentList: curComponentList } = draft
      const { oldIndex, newIndex } = action.payload
      draft.componentList = arrayMove(curComponentList, oldIndex, newIndex)
    }),
  },
})

export const componentAction = componentSlice.actions

export default componentSlice.reducer
